From 33aa61ef2c11d2d12b16ea94f46336a5ab19df23 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Timm=20B=C3=A4der?= Date: Thu, 16 Nov 2017 21:04:18 +0100 Subject: [PATCH] gl renderer: Save clip in every node --- gsk/gskglrenderer.c | 174 ++++++++++++--------- gsk/meson.build | 1 + gsk/resources/glsl/gl3_common.fs.glsl | 85 +++++++++- gsk/resources/glsl/gl3_common.vs.glsl | 1 + gsk/resources/glsl/linear_gradient.fs.glsl | 8 +- gsk/resources/glsl/rounded_clip.fs.glsl | 91 ----------- 6 files changed, 189 insertions(+), 171 deletions(-) diff --git a/gsk/gskglrenderer.c b/gsk/gskglrenderer.c index 948c1e0a37..8904927d5b 100644 --- a/gsk/gskglrenderer.c +++ b/gsk/gskglrenderer.c @@ -57,6 +57,10 @@ typedef struct { int blendMode_location; int viewport_location; int projection_location; + int modelview_location; + int clip_location; + int clip_corner_widths_location; + int clip_corner_heights_location; /* Shader-specific locations */ union { @@ -94,7 +98,6 @@ enum { MODE_TEXTURE, MODE_COLOR_MATRIX, MODE_LINEAR_GRADIENT, - MODE_ROUNDED_CLIP, N_MODES }; @@ -108,6 +111,10 @@ typedef struct { graphene_matrix_t mvp; graphene_matrix_t projection; + graphene_matrix_t modelview; + + /* (Rounded) Clip */ + GskRoundedRect rounded_clip; float opacity; float z; @@ -127,11 +134,6 @@ typedef struct { graphene_point_t start_point; graphene_point_t end_point; } linear_gradient_data; - struct { - graphene_rect_t clip_bounds; - float corner_widths[4]; - float corner_heights[4]; - } rounded_clip_data; }; const char *name; @@ -165,6 +167,10 @@ enum { BLEND_MODE, VIEWPORT, PROJECTION, + MODELVIEW, + CLIP, + CLIP_CORNER_WIDTHS, + CLIP_CORNER_HEIGHTS, N_UNIFORMS }; @@ -216,7 +222,7 @@ struct _GskGLRenderer Program color_program; Program color_matrix_program; Program linear_gradient_program; - Program rounded_clip_program; + Program clip_program; GArray *render_items; @@ -314,6 +320,14 @@ init_common_locations (GskGLRenderer *self, self->uniforms[VIEWPORT]); prog->projection_location = gsk_shader_builder_get_uniform_location (builder, prog->id, self->uniforms[PROJECTION]); + prog->modelview_location = gsk_shader_builder_get_uniform_location (builder, prog->id, + self->uniforms[MODELVIEW]); + prog->clip_location = gsk_shader_builder_get_uniform_location (builder, prog->id, + self->uniforms[CLIP]); + prog->clip_corner_widths_location = gsk_shader_builder_get_uniform_location (builder, prog->id, + self->uniforms[CLIP_CORNER_WIDTHS]); + prog->clip_corner_heights_location = gsk_shader_builder_get_uniform_location (builder, prog->id, + self->uniforms[CLIP_CORNER_HEIGHTS]); prog->position_location = gsk_shader_builder_get_attribute_location (builder, prog->id, self->attributes[POSITION]); @@ -340,6 +354,10 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self, self->uniforms[BLEND_MODE] = gsk_shader_builder_add_uniform (builder, "uBlendMode"); self->uniforms[VIEWPORT] = gsk_shader_builder_add_uniform (builder, "uViewport"); self->uniforms[PROJECTION] = gsk_shader_builder_add_uniform (builder, "uProjection"); + self->uniforms[MODELVIEW] = gsk_shader_builder_add_uniform (builder, "uModelview"); + self->uniforms[CLIP] = gsk_shader_builder_add_uniform (builder, "uClip"); + self->uniforms[CLIP_CORNER_WIDTHS] = gsk_shader_builder_add_uniform (builder, "uClipCornerWidths"); + self->uniforms[CLIP_CORNER_HEIGHTS] = gsk_shader_builder_add_uniform (builder, "uClipCornerHeights"); self->attributes[POSITION] = gsk_shader_builder_add_attribute (builder, "aPosition"); self->attributes[UV] = gsk_shader_builder_add_attribute (builder, "aUv"); @@ -428,7 +446,7 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self, INIT_PROGRAM_UNIFORM_LOCATION (color_matrix_program, color_offset_location, "uColorOffset"); self->linear_gradient_program.id = gsk_shader_builder_create_program (builder, - "linear_gradient.vs.glsl", + "blit.vs.glsl", "linear_gradient.fs.glsl", &shader_error); if (shader_error != NULL) @@ -445,22 +463,6 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self, INIT_PROGRAM_UNIFORM_LOCATION (linear_gradient_program, start_point_location, "uStartPoint"); INIT_PROGRAM_UNIFORM_LOCATION (linear_gradient_program, end_point_location, "uEndPoint"); - self->rounded_clip_program.id = gsk_shader_builder_create_program (builder, - "blit.vs.glsl", - "rounded_clip.fs.glsl", - &shader_error); - if (shader_error != NULL) - { - g_propagate_prefixed_error (error, - shader_error, - "Unable to create 'rounded_clip' program: "); - goto out; - } - init_common_locations (self, builder, &self->rounded_clip_program); - INIT_PROGRAM_UNIFORM_LOCATION (rounded_clip_program, clip_bounds_location, "uClipBounds"); - INIT_PROGRAM_UNIFORM_LOCATION (rounded_clip_program, corner_widths_location, "uCornerWidths"); - INIT_PROGRAM_UNIFORM_LOCATION (rounded_clip_program, corner_heights_location, "uCornerHeights"); - res = TRUE; out: @@ -718,21 +720,6 @@ render_item (GskGLRenderer *self, } break; - case MODE_ROUNDED_CLIP: - { - g_assert (item->program == &self->rounded_clip_program); - glUniform1i (item->program->source_location, 0); - gsk_gl_driver_bind_source_texture (self->gl_driver, item->render_target); - glUniform4f (item->program->clip_bounds_location, - item->rounded_clip_data.clip_bounds.origin.x, - item->rounded_clip_data.clip_bounds.origin.y, - item->rounded_clip_data.clip_bounds.size.width, - item->rounded_clip_data.clip_bounds.size.height); - glUniform4fv (item->program->corner_widths_location, 1, item->rounded_clip_data.corner_widths); - glUniform4fv (item->program->corner_heights_location, 1, item->rounded_clip_data.corner_heights); - } - break; - default: g_assert_not_reached (); } @@ -740,12 +727,30 @@ render_item (GskGLRenderer *self, /* Common uniforms */ graphene_matrix_to_float (&item->mvp, mat); glUniformMatrix4fv (item->program->mvp_location, 1, GL_FALSE, mat); + graphene_matrix_to_float (&item->projection, mat); - glUniformMatrix4fv (item->program->projection_location, 1, GL_FALSE, mat); + glUniformMatrix4fv (item->program->projection_location, 1, GL_TRUE, mat); + + graphene_matrix_to_float (&item->modelview, mat); + glUniformMatrix4fv (item->program->modelview_location, 1, GL_TRUE, mat); glUniform1f (item->program->alpha_location, item->opacity); glUniform4f (item->program->viewport_location, self->viewport.origin.x, self->viewport.origin.y, self->viewport.size.width, self->viewport.size.height); + glUniform4f (item->program->clip_location, + item->rounded_clip.bounds.origin.x, item->rounded_clip.bounds.origin.y, + item->rounded_clip.bounds.size.width, item->rounded_clip.bounds.size.height); + + glUniform4f (item->program->clip_corner_widths_location, + MAX (item->rounded_clip.corner[0].width, 1), + MAX (item->rounded_clip.corner[1].width, 1), + MAX (item->rounded_clip.corner[2].width, 1), + MAX (item->rounded_clip.corner[3].width, 1)); + glUniform4f (item->program->clip_corner_heights_location, + MAX (item->rounded_clip.corner[0].height, 1), + MAX (item->rounded_clip.corner[1].height, 1), + MAX (item->rounded_clip.corner[2].height, 1), + MAX (item->rounded_clip.corner[3].height, 1)); gsk_gl_driver_bind_vao (self->gl_driver, item->vao_id); glDrawArrays (GL_TRIANGLES, 0, N_VERTICES); @@ -805,7 +810,8 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self, const graphene_matrix_t *modelview, GArray *render_items, GskRenderNode *node, - int render_target) + int render_target, + const GskRoundedRect *parent_clip) { RenderItem item; @@ -817,7 +823,8 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self, for (i = 0, p = gsk_container_node_get_n_children (node); i < p; i++) { GskRenderNode *child = gsk_container_node_get_child (node, i); - gsk_gl_renderer_add_render_item (self, projection, modelview, render_items, child, render_target); + gsk_gl_renderer_add_render_item (self, projection, modelview, render_items, + child, render_target, parent_clip); } return; } @@ -826,7 +833,6 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self, item.name = node->name != NULL ? node->name : "unnamed"; - /*g_message ("%s: %s", __FUNCTION__, item.name);*/ item.size.width = node->bounds.size.width; item.size.height = node->bounds.size.height; @@ -836,8 +842,6 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self, item.min.x = node->bounds.origin.x; item.min.y = node->bounds.origin.y; - /*g_message ("%s: %f, %f", item.name, item.min.x, item.min.y);*/ - item.max.x = item.min.x + node->bounds.size.width; item.max.y = item.min.y + node->bounds.size.height; @@ -847,6 +851,8 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self, item.opacity = 1.0; item.projection = *projection; + item.modelview = *modelview; + item.rounded_clip = *parent_clip; item.blend_mode = GSK_BLEND_MODE_DEFAULT; @@ -871,7 +877,7 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self, graphene_matrix_init_identity (&identity); init_framebuffer_for_node (self, &item, node, projection, &p); gsk_gl_renderer_add_render_item (self, &p, &identity, item.children, child, - item.render_target); + item.render_target, parent_clip); } else { @@ -894,39 +900,49 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self, case GSK_CLIP_NODE: { GskRenderNode *child = gsk_clip_node_get_child (node); - graphene_matrix_t p; - graphene_matrix_t identity; + graphene_rect_t transformed_clip; + graphene_rect_t intersection; + GskRoundedRect child_clip; - graphene_matrix_init_identity (&identity); - init_framebuffer_for_node (self, &item, node, projection, &p); - gsk_gl_renderer_add_render_item (self, &p, &identity, item.children, child, - item.render_target); - item.mode = MODE_BLIT; + transformed_clip = *gsk_clip_node_peek_clip (node); + graphene_matrix_transform_bounds (modelview, &transformed_clip, &transformed_clip); + + /* Since we do the intersection here, we also need to transform by the modelview matrix. + * We can't do it in the shader. Same with rounded clips */ + graphene_rect_intersection (&transformed_clip, + &parent_clip->bounds, + &intersection); + + gsk_rounded_rect_init_from_rect (&child_clip, &intersection, 0.0f); + + gsk_gl_renderer_add_render_item (self, projection, modelview, render_items, child, + render_target, &child_clip); } - break; + return; case GSK_ROUNDED_CLIP_NODE: { GskRenderNode *child = gsk_rounded_clip_node_get_child (node); - const GskRoundedRect *clip = gsk_rounded_clip_node_peek_clip (node); - graphene_matrix_t p; - graphene_matrix_t identity; - int i; - - graphene_matrix_init_identity (&identity); - init_framebuffer_for_node (self, &item, node, projection, &p); - gsk_gl_renderer_add_render_item (self, &p, &identity, item.children, child, - item.render_target); - item.mode = MODE_ROUNDED_CLIP; - item.program = &self->rounded_clip_program; - item.rounded_clip_data.clip_bounds = clip->bounds; - for (i = 0; i < 4; i ++) - { - item.rounded_clip_data.corner_widths[i] = MAX (clip->corner[i].width, 1); - item.rounded_clip_data.corner_heights[i] = MAX (clip->corner[i].height, 1); - } + const GskRoundedRect *rounded_clip = gsk_rounded_clip_node_peek_clip (node); + graphene_rect_t transformed_clip; + graphene_rect_t intersection; + GskRoundedRect child_clip; + + transformed_clip = rounded_clip->bounds; + graphene_matrix_transform_bounds (modelview, &transformed_clip, &transformed_clip); + + graphene_rect_intersection (&transformed_clip, &parent_clip->bounds, + &intersection); + gsk_rounded_rect_init (&child_clip, &intersection, + &rounded_clip->corner[0], + &rounded_clip->corner[1], + &rounded_clip->corner[2], + &rounded_clip->corner[3]); + + gsk_gl_renderer_add_render_item (self, projection, modelview, render_items, child, + render_target, &child_clip); } - break; + return; case GSK_COLOR_MATRIX_NODE: { @@ -941,7 +957,7 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self, graphene_matrix_init_identity (&identity); init_framebuffer_for_node (self, &item, node, projection, &p); gsk_gl_renderer_add_render_item (self, &p, &identity, item.children, child, - item.render_target); + item.render_target, parent_clip); } else { @@ -1044,10 +1060,12 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self, graphene_matrix_init_from_matrix (&transform, gsk_transform_node_peek_transform (node)); graphene_matrix_multiply (&transform, modelview, &transformed_mv); gsk_gl_renderer_add_render_item (self, - projection, &transformed_mv, + projection, + &transformed_mv, render_items, gsk_transform_node_get_child (node), - render_target); + render_target, + parent_clip); } return; @@ -1157,12 +1175,16 @@ gsk_gl_renderer_validate_tree (GskGLRenderer *self, const graphene_matrix_t *projection) { graphene_matrix_t modelview; + GskRoundedRect viewport_clip; + graphene_matrix_init_scale (&modelview, self->scale_factor, self->scale_factor, 1.0f); gdk_gl_context_make_current (self->gl_context); + gsk_rounded_rect_init_from_rect (&viewport_clip, &self->viewport, 0.0f); + gsk_gl_renderer_add_render_item (self, projection, &modelview, self->render_items, root, - self->texture_id); + self->texture_id, &viewport_clip); } static void diff --git a/gsk/meson.build b/gsk/meson.build index 18208267b7..215e5a60a9 100644 --- a/gsk/meson.build +++ b/gsk/meson.build @@ -10,6 +10,7 @@ gsk_private_source_shaders = [ 'resources/glsl/linear_gradient.fs.glsl', 'resources/glsl/linear_gradient.vs.glsl', 'resources/glsl/rounded_clip.fs.glsl', + 'resources/glsl/clip.fs.glsl', 'resources/glsl/es2_common.fs.glsl', 'resources/glsl/es2_common.vs.glsl', 'resources/glsl/gl3_common.fs.glsl', diff --git a/gsk/resources/glsl/gl3_common.fs.glsl b/gsk/resources/glsl/gl3_common.fs.glsl index f1c9bdf681..ad465bc8f7 100644 --- a/gsk/resources/glsl/gl3_common.fs.glsl +++ b/gsk/resources/glsl/gl3_common.fs.glsl @@ -4,18 +4,101 @@ uniform sampler2D uSource; uniform sampler2D uMask; uniform mat4 uMVP; uniform mat4 uProjection = mat4(1.0); +uniform mat4 uModelview = mat4(1.0); uniform float uAlpha = 1.0; uniform int uBlendMode; uniform vec4 uViewport; +// In GtkSnapshot coordinates +uniform vec4 uClip; +uniform vec4 uClipCornerWidths = vec4(1, 1, 1, 1); +uniform vec4 uClipCornerHeights = vec4(1, 1, 1, 1); + in vec2 vUv; out vec4 outputColor; + +struct RoundedRect +{ + vec4 bounds; + vec4 corner_widths; + vec4 corner_heights; +}; + +float +ellipsis_dist (vec2 p, vec2 radius) +{ + vec2 p0 = p / radius; + vec2 p1 = 2.0 * p0 / radius; + + return (dot(p0, p0) - 1.0) / length (p1); +} + +float +ellipsis_coverage (vec2 point, vec2 center, vec2 radius) +{ + float d = ellipsis_dist (point - center, radius); + return clamp (0.5 - d, 0.0, 1.0); +} + +float +rounded_rect_coverage (RoundedRect r, vec2 p) +{ + if (p.x < r.bounds.x || p.y < r.bounds.y || + p.x >= r.bounds.z || p.y >= r.bounds.w) + return 0.0; + + vec2 rad_tl = vec2(r.corner_widths.x, r.corner_heights.x); + vec2 rad_tr = vec2(r.corner_widths.y, r.corner_heights.y); + vec2 rad_br = vec2(r.corner_widths.z, r.corner_heights.z); + vec2 rad_bl = vec2(r.corner_widths.w, r.corner_heights.w); + + vec2 ref_tl = r.bounds.xy + vec2( r.corner_widths.x, r.corner_heights.x); + vec2 ref_tr = r.bounds.zy + vec2(-r.corner_widths.y, r.corner_heights.y); + vec2 ref_br = r.bounds.zw + vec2(-r.corner_widths.z, -r.corner_heights.z); + vec2 ref_bl = r.bounds.xw + vec2( r.corner_widths.w, -r.corner_heights.w); + + float d_tl = ellipsis_coverage(p, ref_tl, rad_tl); + float d_tr = ellipsis_coverage(p, ref_tr, rad_tr); + float d_br = ellipsis_coverage(p, ref_br, rad_br); + float d_bl = ellipsis_coverage(p, ref_bl, rad_bl); + + vec4 corner_coverages = 1.0 - vec4(d_tl, d_tr, d_br, d_bl); + + bvec4 is_out = bvec4(p.x < ref_tl.x && p.y < ref_tl.y, + p.x > ref_tr.x && p.y < ref_tr.y, + p.x > ref_br.x && p.y > ref_br.y, + p.x < ref_bl.x && p.y > ref_bl.y); + + return 1.0 - dot(vec4(is_out), corner_coverages); +} + +RoundedRect +rounded_rect_shrink (RoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_widths = max (r.corner_widths - amount.wyyw, 0.0); + vec4 new_heights = max (r.corner_heights - amount.xxzz, 0.0); + + return RoundedRect (new_bounds, new_widths, new_heights); +} + vec4 Texture(sampler2D sampler, vec2 texCoords) { return texture(sampler, texCoords); } void setOutputColor(vec4 color) { - outputColor = color; + vec4 clipBounds = uClip; + vec4 f = gl_FragCoord; + + f.x += uViewport.x; + f.y = (uViewport.y + uViewport.w) - f.y; + + clipBounds.z = clipBounds.x + clipBounds.z; + clipBounds.w = clipBounds.y + clipBounds.w; + + RoundedRect r = RoundedRect(clipBounds, uClipCornerWidths, uClipCornerHeights); + + outputColor = color * rounded_rect_coverage(r, f.xy); } diff --git a/gsk/resources/glsl/gl3_common.vs.glsl b/gsk/resources/glsl/gl3_common.vs.glsl index f82f99c399..9794cf0bce 100644 --- a/gsk/resources/glsl/gl3_common.vs.glsl +++ b/gsk/resources/glsl/gl3_common.vs.glsl @@ -1,5 +1,6 @@ uniform mat4 uMVP; uniform mat4 uProjection; +//uniform mat4 uModelview; in vec2 aPosition; in vec2 aUv; diff --git a/gsk/resources/glsl/linear_gradient.fs.glsl b/gsk/resources/glsl/linear_gradient.fs.glsl index cbbc71cc4b..d107e8a1ef 100644 --- a/gsk/resources/glsl/linear_gradient.fs.glsl +++ b/gsk/resources/glsl/linear_gradient.fs.glsl @@ -12,13 +12,15 @@ vec4 fragCoord() { } void main() { - float maxDist = length(uEndPoint - uStartPoint); + vec2 startPoint = (vec4(uStartPoint, 0, 1) * uModelview).xy; + vec2 endPoint = (vec4(uEndPoint, 0, 1) * uModelview).xy; + float maxDist = length(endPoint - startPoint); // Position relative to startPoint - vec2 pos = fragCoord().xy - uStartPoint; + vec2 pos = fragCoord().xy - startPoint; // Gradient direction - vec2 gradient = uEndPoint - uStartPoint; + vec2 gradient = endPoint - startPoint; float gradientLength = length(gradient); // Current pixel, projected onto the line between the start point and the end point diff --git a/gsk/resources/glsl/rounded_clip.fs.glsl b/gsk/resources/glsl/rounded_clip.fs.glsl index 5589c12e79..e69de29bb2 100644 --- a/gsk/resources/glsl/rounded_clip.fs.glsl +++ b/gsk/resources/glsl/rounded_clip.fs.glsl @@ -1,91 +0,0 @@ -uniform vec4 uClipBounds; -uniform vec4 uCornerWidths; -uniform vec4 uCornerHeights; - -struct RoundedRect -{ - vec4 bounds; - vec4 corner_widths; - vec4 corner_heights; -}; - -float -ellipsis_dist (vec2 p, vec2 radius) -{ - vec2 p0 = p / radius; - vec2 p1 = 2.0 * p0 / radius; - - return (dot(p0, p0) - 1.0) / length (p1); -} - -float -ellipsis_coverage (vec2 point, vec2 center, vec2 radius) -{ - float d = ellipsis_dist (point - center, radius); - return clamp (0.5 - d, 0.0, 1.0); -} - -float -rounded_rect_coverage (RoundedRect r, vec2 p) -{ - if (p.x < r.bounds.x || p.y < r.bounds.y || - p.x >= r.bounds.z || p.y >= r.bounds.w) - return 0.0; - - vec2 rad_tl = vec2(r.corner_widths.x, r.corner_heights.x); - vec2 rad_tr = vec2(r.corner_widths.y, r.corner_heights.y); - vec2 rad_br = vec2(r.corner_widths.z, r.corner_heights.z); - vec2 rad_bl = vec2(r.corner_widths.w, r.corner_heights.w); - - vec2 ref_tl = r.bounds.xy + vec2( r.corner_widths.x, r.corner_heights.x); - vec2 ref_tr = r.bounds.zy + vec2(-r.corner_widths.y, r.corner_heights.y); - vec2 ref_br = r.bounds.zw + vec2(-r.corner_widths.z, -r.corner_heights.z); - vec2 ref_bl = r.bounds.xw + vec2( r.corner_widths.w, -r.corner_heights.w); - - float d_tl = ellipsis_coverage(p, ref_tl, rad_tl); - float d_tr = ellipsis_coverage(p, ref_tr, rad_tr); - float d_br = ellipsis_coverage(p, ref_br, rad_br); - float d_bl = ellipsis_coverage(p, ref_bl, rad_bl); - - vec4 corner_coverages = 1.0 - vec4(d_tl, d_tr, d_br, d_bl); - - bvec4 is_out = bvec4(p.x < ref_tl.x && p.y < ref_tl.y, - p.x > ref_tr.x && p.y < ref_tr.y, - p.x > ref_br.x && p.y > ref_br.y, - p.x < ref_bl.x && p.y > ref_bl.y); - - return 1.0 - dot(vec4(is_out), corner_coverages); -} - -RoundedRect -rounded_rect_shrink (RoundedRect r, vec4 amount) -{ - vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; - vec4 new_widths = max (r.corner_widths - amount.wyyw, 0.0); - vec4 new_heights = max (r.corner_heights - amount.xxzz, 0.0); - - return RoundedRect (new_bounds, new_widths, new_heights); -} - -vec4 fragCoord() { - vec4 f = gl_FragCoord; - f.x += uViewport.x; - f.y = (uViewport.y + uViewport.w) - f.y; - return f; -} - -vec4 clip(vec4 color) { - vec4 bounds = uClipBounds; - bounds.z = bounds.x + bounds.z; - bounds.w = bounds.y + bounds.w; - - RoundedRect r = RoundedRect(bounds, uCornerWidths, uCornerHeights); - - return color * rounded_rect_coverage(r, fragCoord().xy); -} - -void main() { - vec4 diffuse = Texture(uSource, vUv); - - setOutputColor(clip(diffuse) * uAlpha); -} -- 2.30.2